import numpy as np
from dataloader import PointData, GraphData
from iterative_mutisided_positioning import IterativeMutisidedPosition
from dv_hop_positioning import DV_Hop_Positioning
from utils import RMSE
import logging

if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, format='%(filename)s:%(lineno)s-%(levelname)s:\t%(message)s')

task_print = print if __name__ == "__main__" else lambda *args, **kwargs: logging.info(" ".join(map(str, args)), **kwargs)

def run_and_cal_iterative_mutisided_positioning(points_data_path, graph_path):
    points_data = PointData(points_data_path)
    graph = GraphData(graph_path)
    
    logging.info("####################################################"*2)
    logging.info(f"points_path: {points_data_path}, graph_path: {graph_path}")
    
    archor_points_dict = points_data.anchor_data_dict()
    positioning = IterativeMutisidedPosition(archor_points_dict, graph)
    
    cal_points = positioning.run()
    
    logging.debug(f"cal_points: {cal_points}")
    
    cal_points_idx = sorted(cal_points.keys())
    predicted = np.array([cal_points[idx] for idx in cal_points_idx])
    real = np.array(points_data.get_points(cal_points_idx))
    
    logging.debug(f"predicted: \n{predicted}")
    logging.debug(f"real: \n{real}")
    logging.info(f"delta: \n{predicted - real}")
    
    rmse = RMSE(predicted, real)
    
    logging.info(f"RMSE: {rmse}")
    
    return rmse

def run_and_cal_dv_hop_positioning(points_data_path, graph_path):
    points_data = PointData(points_data_path)
    graph = GraphData(graph_path)
    logging.info("####################################################"*2)
    logging.info(f"points_path: {points_data_path}, graph_path: {graph_path}")
    positioning = DV_Hop_Positioning(points_data, graph)
    cal_points = positioning.run()
    logging.debug(f"cal_points: {cal_points}")
    cal_points_idx = sorted(cal_points.keys())
    predicted = np.array([cal_points[idx] for idx in cal_points_idx])
    real = np.array(points_data.get_points(cal_points_idx))
    logging.debug(f"predicted: \n{predicted}")
    logging.debug(f"real: \n{real}")
    logging.info(f"delta: \n{predicted - real}")
    rmse = RMSE(predicted, real)
    logging.info(f"RMSE: {rmse}")
    return rmse

def task_1():
    """
    方法1, 
    根据无误差、增加了5%和10%误差之后的距离信息, 
    使用迭代多边定位算法计算出所有未知节点坐标, 
    与net1_pos.txt所给的未知节点的真实坐标,计算均方根误差。
    """
    task_print("task_1 begin:")
    points_data_path = "./data/net1_pos.txt"
    graph_ground_truth_path = "./data/net1_topo_error_0.txt"
    graph_error5_path = "./data/net1_topo_error_5.txt"
    graph_error10_path = "./data/net1_topo_error_10.txt"
    error_0_RMSE = run_and_cal_iterative_mutisided_positioning(points_data_path, graph_ground_truth_path)
    task_print(f"error_0 RMSE: {error_0_RMSE}")
    error5RMSE = run_and_cal_iterative_mutisided_positioning(points_data_path, graph_error5_path)
    task_print(f"error5 RMSE: {error5RMSE}")
    error10RMSE = run_and_cal_iterative_mutisided_positioning(points_data_path, graph_error10_path)
    task_print(f"error10 RMSE: {error10RMSE}")
    task_print("task_1 end.\n")
    return error_0_RMSE, error5RMSE, error10RMSE

def task_2():
    """
    根据net1_topo_error_free.txt得到节点间跳数信息,
    使用DV-Hop算法计算出所有未知节点坐标,
    与net1_pos.txt所给的未知节点的真实坐标,计算均方根误差。
    """
    task_print("task_2 begin:")
    points_data_path = "./data/net1_pos.txt"
    graph_ground_truth_path = "./data/net1_topo_error_0.txt"
    graph_error5_path = "./data/net1_topo_error_5.txt"
    graph_error10_path = "./data/net1_topo_error_10.txt"
    rmse = run_and_cal_dv_hop_positioning(points_data_path, graph_ground_truth_path)
    task_print(f"RMSE : {rmse}")
    task_print("task_2 end.\n")
    return rmse

if __name__ == "__main__":
    task_1()
    task_2()